#pragma once
#include "../common/net.hpp"
#include "../common/message.hpp"

namespace rpc
{
    namespace server
    {
        enum class VType
        {
            BOOL = 0,
            INTEGRAL,
            NUMERIC,
            STRING,
            ARRAY,
            OBJECT
        };

        class ServerDescribe
        {
        public:
            using ptr = std::shared_ptr<ServerDescribe>;
            using ServiceCallback = std::function<void(const Json::Value &, Json::Value &)>;
            using ParamDescribe = std::pair<std::string, VType>;

            ServerDescribe(std::string &&name, std::vector<ParamDescribe> &&desc, ServiceCallback &&_handler, VType rtype)
                : _callback(_handler),
                  _method_name(name),
                  _params_desc(desc),
                  _return_type(rtype)
            {
            }
            const std::string &method() { return _method_name; }
            bool paramCheck(const Json::Value &params)
            {
                // for (auto &desc : _params_desc)
                // {
                //     DLOG("%s",desc.first.c_str());
                // }
                for (auto &desc : _params_desc)
                {
                    if (params.isMember(desc.first) == false) //params是否包含desc.first
                    {
                        // //测试
                        // std::string stu;
                        // JSON::serialize(params,stu);
                        // DLOG("%s",stu.c_str());
                        // //
                        ELOG("参数字段完整性校验失败！%s 字段缺失！", desc.first.c_str());
                        return false;
                    }
                    if (check(desc.second, params[desc.first]) == false)
                    {
                        ELOG("%s 参数类型校验失败！", desc.first.c_str());
                        return false;
                    }
                }
                return true;
            }
            bool call(const Json::Value &params, Json::Value &result)
            {
                _callback(params, result);//根据参数获取结果
                if (rtypeCheck(result) == false)
                {
                    ELOG("回调处理函数中的响应信息校验失败！");
                    return false;
                }
                return true;
            }

        private:
            bool rtypeCheck(const Json::Value &val)
            {
                return check(_return_type, val);
            }
            bool check(VType rtype, const Json::Value &val)
            {
                switch (rtype)
                {
                case VType::BOOL:
                    return val.isBool();
                case VType::INTEGRAL:
                    return val.isIntegral();
                case VType::NUMERIC:
                    return val.isNumeric();
                case VType::STRING:
                    return val.isString();
                case VType::ARRAY:
                    return val.isArray();
                case VType::OBJECT:
                    return val.isObject();
                }
                return false;
            }

        private:
            ServiceCallback _callback;               // 业务回调函数
            std::string _method_name;                // 方法名称
            std::vector<ParamDescribe> _params_desc; // 参数字段格式描述,参数以及参数对应的类型
            rpc::server::VType _return_type;         // 方法返回值类型
        };

        class SDescribeFactory
        {
        public:
            using ptr = std::shared_ptr<SDescribeFactory>;
            void setmethod(const std::string& name) { _method_name = name; }
            void setCallback(const ServerDescribe::ServiceCallback& handler) { _callback = handler; }
            void setParamsdesc(const std::string &pname , VType type){ _params_desc.push_back(ServerDescribe::ParamDescribe({pname,type})); }
            void setVtype(const VType type) { _return_type = type; } 
            ServerDescribe::ptr build()
            {
                return std::make_shared<ServerDescribe>(std::move(_method_name), std::move(_params_desc),std::move( _callback),_return_type);
            }
        private:
            ServerDescribe::ServiceCallback _callback;               // 业务回调函数
            std::string _method_name;                // 方法名称
            std::vector<ServerDescribe::ParamDescribe> _params_desc; // 参数字段格式描述
            VType _return_type;         // 方法返回值类型
        };

        class ServiceManage
        {
        public:
            using ptr = std::shared_ptr<ServiceManage>;
            void insert(const ServerDescribe::ptr &desc)
            {
                std::unique_lock<std::mutex> lock(_mtx);
                _services.insert(std::make_pair(desc->method(),desc));
            }

            ServerDescribe::ptr select(const std::string &method_name)
            {
                std::unique_lock<std::mutex> lock(_mtx);
                auto it = _services.find(method_name);
                if(it == _services.end())
                {
                    return ServerDescribe::ptr();
                }
                return it->second;
            }
            void remove(const std::string &method_name)
            {
                std::unique_lock<std::mutex> lock(_mtx);
                _services.erase(method_name);
            }
        private:
            std::mutex _mtx;
            std::unordered_map<std::string,ServerDescribe::ptr> _services;
        };
        class RpcRouter
        {
        public:
            using ptr = std::shared_ptr<RpcRouter>;
            RpcRouter() : _service_manage(std::make_shared<ServiceManage>())
            {}
            //注册到Dispatch模块中对Rpc请求进行回调处理的业务函数
            void onRpcRequest(const BaseConnection::ptr conn,RpcRequest::ptr &request)
            {
                auto service = _service_manage->select(request->method());
                //1. 查询客户端请求的方法描述--判断当前服务端能否提供对应的服务
                if(service.get() == nullptr)
                {
                    ELOG("%s 服务未找到！", request->method().c_str());
                     //ServerDescribe  : desc;
                    return response(conn,request,Json::Value(),Rcode::RCODE_NOT_FOUND_SERVICE);
                }
                //2. 进行参数校验，确定能否提供服务
                if(service->paramCheck(request->params()) == false)
                {
                    ELOG("%s 服务参数校验失败！", request->method().c_str());
                    return response(conn, request, Json::Value(), Rcode::RCODE_INVALID_PARAMS);
                }
                //3. 调用业务回调接口进行业务处理
                Json::Value result;
                bool ret = service->call(request->params(),result);//调用回调函数针对请求进行处理
                if (ret == false) {
                    ELOG("%s 服务参数校验失败！", request->method().c_str());
                    return response(conn, request, Json::Value(), Rcode::RCODE_INTERNAL_ERROR);
                }
                //4. 处理完毕得到结果，组织响应，向客户端发送
                return response(conn,request,result,Rcode::RCODE_OK);
            }
            void RegisterMethod(const ServerDescribe::ptr &svr)
            {
                _service_manage->insert(svr);
            }
        private:
            void response(const BaseConnection::ptr& conn,const RpcRequest::ptr &req,const Json::Value &result,Rcode rcode)
            {
                auto msg = MessageFactory::create<RpcResponse>();
                msg->setid(req->id());
                msg->setmtype(rpc::Mtype::RSP_RPC);
                msg->setRcode(rcode);
                msg->setResult(result);
                conn->send(msg);
            }
        private:
            ServiceManage::ptr _service_manage;
        };

    }
}